using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using KS.Gantt;
using KS.Gantt.Dialogs.Controls;
using Calendar;

namespace MiGuava
{
    public partial class ucSchedule : UserControl
    {
        public object DataSource
        {
            get
            {
                return bindingSource1.DataSource;
            }
            set
            {
                bindingSource1.DataSource = value;
            }
        }

        protected KS.Gantt.Gantt m_GanttControl = null;
        public KS.Gantt.Gantt GanttControl
        {
            get
            {
                return m_GanttControl;
            }
            set
            {
                if (m_GanttControl != value)
                {
                    m_GanttControl = value;

                    if (m_GanttControl != null)
                    {                        
                        InitData();
                        m_GanttControl.MinMaxDateChanged += new EventHandler(m_GanttControl_MinMaxDateChanged);
                    }
                }                
            }
        }        

        void m_GanttControl_MinMaxDateChanged(object sender, EventArgs e)
        {
            if (m_GanttControl.MaxDate > m_GanttControl.MinDate)
            {
                try
                {
                    monthCalendar1.MinDate = new DateTime(1753, 1, 1);
                    monthCalendar1.MaxDate = m_GanttControl.MaxDate;
                    monthCalendar1.MinDate = m_GanttControl.MinDate;
                }
                catch (Exception)
                {                    
                }                
            }
            else
            {
                try
                {
                    monthCalendar1.MinDate = new DateTime(1753, 1, 1);
                    monthCalendar1.MaxDate = new DateTime(9998, 12, 31);
                }
                catch (Exception)
                {                    
                }                
            }
        }

        void WorkingDays_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            SetWorkingHours();
        }               

        public ucSchedule()
        {
            InitializeComponent();
            
            GRD.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            GRD.MultiSelect = false;
            GRD.AllowUserToAddRows = false;
            GRD.AllowUserToResizeRows = false;
            
            GRD.RowHeadersWidth = 24;
            GRD.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;

            GRD.DataSource = bindingSource1;
            
            monthCalendar1.DateChanged += new DateRangeEventHandler(monthCalendar1_DateChanged);
            GRD.SelectionChanged += new EventHandler(GRD_SelectionChanged);
            
            dayView1.AllowNew = false;            
            dayView1.AllowInplaceEditing = false;            
            dayView1.ResolveAppointments += new Calendar.ResolveAppointmentsEventHandler(dayView1_ResolveAppointments);
            

            dayView1.MouseDown += new MouseEventHandler(dayView1_MouseDown);
            dayView1.DoubleClick += new EventHandler(dayView1_DoubleClick);

            radProjectSchedule.CheckedChanged += new EventHandler(radProjectSchedule_CheckedChanged);            
        }        

        Point LastMouseDown;
        void dayView1_MouseDown(object sender, MouseEventArgs e)
        {
            LastMouseDown = new Point(e.X, e.Y);
        }

        void dayView1_DoubleClick(object sender, EventArgs e)
        {
            Appointment app = dayView1.GetAppointmentAt(LastMouseDown.X, LastMouseDown.Y);
            if (app != null && app.Tag != null)
            {
                string key = app.Tag.ToString();
                TaskItem task = m_GanttControl.Tasks.FindItemByKey(key);
                if (task != null)
                {
                    Program.CursorWait();
                    m_GanttControl.EditItem(task);
                }
            }
        }

        void radProjectSchedule_CheckedChanged(object sender, EventArgs e)
        {
            InitData();
            dayView1.Invalidate();
        }

        private void SetBoldedDates()
        {

            // great idea, but this may take far too long ..
            return;

            //monthCalendar1.RemoveAllBoldedDates();

            //if (radProjectSchedule.Checked)
            //{
            //    foreach (TaskItem task in m_GanttControl.Tasks)
            //    {                    
            //        DateTime dt = task.StartDate.Date;
            //        while (dt < task.EndDate)
            //        {                        
            //            if (dayView1.GanttCalendar.IsWorkingDay(dt))
            //                monthCalendar1.AddBoldedDate(dt);

            //            dt = dt.AddDays(1);
            //        }                 
            //    }
            //}
            //else
            //{
            //    if (GRD.CurrentRow != null && GRD.CurrentRow.DataBoundItem is ResourceItem)
            //    {
            //        ResourceItem resource = (ResourceItem)GRD.CurrentRow.DataBoundItem;
            //        foreach (TaskItem task in resource.AssignedTasks)
            //        {                        
            //            DateTime dt = task.StartDate.Date;
            //            while (dt < task.EndDate)
            //            {
            //                if (dayView1.GanttCalendar.IsWorkingDay(dt))
            //                    monthCalendar1.AddBoldedDate(dt);

            //                dt = dt.AddDays(1);
            //            } 
            //        }
            //    }                
            //}

            //monthCalendar1.UpdateBoldedDates();
        }        

        private void SetWorkingHours()
        {
            if (radProjectSchedule.Checked)
            {
                if (GRD.CurrentRow != null && GRD.CurrentRow.DataBoundItem is TaskItem)
                {
                    TaskItem task = (TaskItem)GRD.CurrentRow.DataBoundItem;
                    dayView1.GanttCalendar = task.CombinedCalendar;
                }
                else
                    dayView1.GanttCalendar = m_GanttControl.DefaultCalendar;
            }
            else
            {
                if (GRD.CurrentRow != null && GRD.CurrentRow.DataBoundItem is ResourceItem)
                {
                    ResourceItem resource = (ResourceItem)GRD.CurrentRow.DataBoundItem;
                    dayView1.GanttCalendar = resource.CombinedCalendar;
                }
                else
                    dayView1.GanttCalendar = null;
            }
        }

        void dayView1_ResolveAppointments(object sender, Calendar.ResolveAppointmentsEventArgs args)
        {               
            List<Appointment> m_Apps = new List<Appointment>();
            TimeSpan ts = args.EndDate.Subtract(args.StartDate);

            KS.Gantt.Calendars.Calendar calendar;

            if (radProjectSchedule.Checked)
            {                
                calendar = m_GanttControl.DefaultCalendar;

                foreach (TaskItem task in m_GanttControl.Tasks)
                {
                    // Milestones don't have a date extension
                    // show them as a half hour task..
                    DateTime TaskEndDate;
                    if (task.IsMilestone)
                        TaskEndDate = task.StartDate.AddHours(0.5d);
                    else
                        TaskEndDate = task.EndDate;

                    if (KS.Gantt.Helpers.DateTimeIntersect(args.StartDate, args.EndDate, task.StartDate, TaskEndDate).TotalDays > 0)
                    {
                        for (int i = 0; i < (int)ts.TotalDays; i++)
                        {
                            Appointment app = null;

                            DateTime dtCurrent = args.StartDate.Date.AddDays(i);

                            if (!calendar.IsWorkingDay(dtCurrent))
                                continue;

                            KS.Gantt.Calendars.WorkingHourCollection whc = calendar.InheritedWorkingHours(dtCurrent);

                            foreach (KS.Gantt.Calendars.WorkingHour wh in whc)
                            {
                                DateTime whStartDate = dtCurrent.Date.AddHours(wh.StartHour);
                                DateTime whEndDate = dtCurrent.Date.AddHours(wh.EndHour);

                                if (KS.Gantt.Helpers.DateTimeIntersect(task.StartDate, TaskEndDate, whStartDate, whEndDate).TotalDays > 0)
                                {
                                    app = new Appointment();

                                    if (task.StartDate >= whStartDate)
                                        app.StartDate = task.StartDate;
                                    else
                                        app.StartDate = whStartDate;

                                    if (TaskEndDate >= whEndDate)
                                        app.EndDate = whEndDate;
                                    else
                                        app.EndDate = TaskEndDate;

                                    app.Color = task.FormatStyle.BackgroundStyle.Color;
                                    app.BorderColor = task.FormatStyle.BorderStyle.Color;
                                    app.Title = task.Text;
                                    app.Tag = task.Key;

                                    m_Apps.Add(app);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                if (GRD.CurrentRow == null || !(GRD.CurrentRow.DataBoundItem is ResourceItem))
                    return;                

                ResourceItem resource = (ResourceItem)GRD.CurrentRow.DataBoundItem;                                

                if (resource == null || resource.ResourceAllocations == null)
                    return;

                calendar = resource.CombinedCalendar;

                foreach (ResourceAllocation ra in resource.ResourceAllocations)
                {                    
                    if (KS.Gantt.Helpers.DateTimeIntersect(args.StartDate, args.EndDate, ra.StartDate, ra.EndDate).TotalDays > 0)
                    {
                        for (int i = 0; i < (int)ts.TotalDays; i++)
                        {
                            Appointment app = null;

                            DateTime dtCurrent = args.StartDate.Date.AddDays(i);

                            if (!calendar.IsWorkingDay(dtCurrent))
                                continue;

                            KS.Gantt.Calendars.WorkingHourCollection whc = calendar.InheritedWorkingHours(dtCurrent);

                            foreach (KS.Gantt.Calendars.WorkingHour wh in whc)
                            {
                                DateTime whStartDate = dtCurrent.Date.AddHours(wh.StartHour);
                                DateTime whEndDate = dtCurrent.Date.AddHours(wh.EndHour);

                                if (KS.Gantt.Helpers.DateTimeIntersect(ra.StartDate, ra.EndDate, whStartDate, whEndDate).TotalDays > 0)
                                {
                                    app = new Appointment();

                                    if (ra.StartDate >= whStartDate)
                                        app.StartDate = ra.StartDate;
                                    else
                                        app.StartDate = whStartDate;

                                    if (ra.EndDate >= whEndDate)
                                        app.EndDate = whEndDate;
                                    else
                                        app.EndDate = ra.EndDate;

                                    TaskItem task = m_GanttControl.Tasks.FindItemByKey(ra.TaskKey);

                                    if (task != null)
                                    {
                                        app.Color = task.FormatStyle.BackgroundStyle.Color;
                                        app.BorderColor = task.FormatStyle.BorderStyle.Color;
                                        app.Title = "[" + m_GanttControl.Project.Text + "]\r\n" + task.Text + "\r\n" + ((double)(ra.Unit * 100)).ToString("n0") + "%";
                                        app.Tag = task.Key;
                                    }
                                    else
                                    {
                                        app.Color = Color.FromArgb(40, m_GanttControl.DefaultBarFormatStyle.BackgroundStyle.Color);
                                        app.BorderColor = Color.FromArgb(40, m_GanttControl.DefaultBarFormatStyle.BorderStyle.Color);
                                        app.Title = "[" + ra.ProjectText + "]\r\n" + ra.TaskText + "\r\n" + ((double)(ra.Unit * 100)).ToString("n0") + "%";
                                        app.Tag = ra.TaskKey;
                                    }

                                    m_Apps.Add(app);
                                }
                            }
                        }
                    }
                }
            }
            
            

            args.Appointments = m_Apps;
        }        

        void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e)
        {
            dayView1.StartDate = monthCalendar1.SelectionStart;
            dayView1.DaysToShow = (int)Math.Min(7, Math.Max(1, ((TimeSpan)monthCalendar1.SelectionEnd.Subtract(monthCalendar1.SelectionStart)).TotalDays + 1));            
        }        

        void GRD_SelectionChanged(object sender, EventArgs e)
        {
            if (GRD.CurrentRow == null)
            {                
                return;
            }

            if (GRD.CurrentRow.DataBoundItem is TaskItem)
            {
                DateTime dtStart = ((TaskItem)GRD.CurrentRow.DataBoundItem).StartDate;
                DateTime dtEnd = ((TaskItem)GRD.CurrentRow.DataBoundItem).EndDate;

                if (dtEnd == DateTime.MinValue || dtStart == DateTime.MaxValue)
                    return;

                if (dtStart > dtEnd)
                    return;

                if (dtStart < monthCalendar1.MinDate)
                    monthCalendar1.MinDate = dtStart;

                if (dtEnd > monthCalendar1.MaxDate)
                    monthCalendar1.MaxDate = dtEnd;
                                
                monthCalendar1.SelectionEnd = dtEnd;
                monthCalendar1.SelectionStart = dtStart;

                SetWorkingHours();
            }
            else if (GRD.CurrentRow.DataBoundItem is ResourceItem)
            {
                SetWorkingHours();
                SetBoldedDates();
                monthCalendar1_DateChanged(null, null);
            }                            
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (this.Visible && radResourceSchedule.Checked && m_GanttControl != null)
                m_GanttControl.UpdateResourceAllocations();
        }

        public void InitData()
        {            
            // ************* DataGRID *************

            GRD.Columns.Clear();

            GRD.AutoGenerateColumns = false;

            if (radProjectSchedule.Checked)
                this.DataSource = m_GanttControl.Tasks;
            else
            {
                this.DataSource = m_GanttControl.Resources;

                if (m_GanttControl != null)
                    m_GanttControl.UpdateResourceAllocations();
            }

            // SetUp custom edit controls            

            // Text
            DataGridViewTextBoxColumn txtText = new DataGridViewTextBoxColumn();
            txtText.DataPropertyName = "Text";
            txtText.HeaderText = "Text";
            txtText.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
            txtText.ReadOnly = true;
            GRD.Columns.Add(txtText);            

            SetWorkingHours();            

            m_GanttControl.DefaultCalendar.WorkingDays.PropertyChanged -= new PropertyChangedEventHandler(WorkingDays_PropertyChanged);

            if (radProjectSchedule.Checked)
            {                
                m_GanttControl.DefaultCalendar.WorkingDays.PropertyChanged += new PropertyChangedEventHandler(WorkingDays_PropertyChanged);
            }            

            // Workaround: monthCalendar1_DateChanged is not called properly
            // during GRD_SelectionChanged
            // We must call it explicitely here            
            monthCalendar1_DateChanged(null, null);
        }
    }
}
